﻿using System;
using System.IO;
using System.Linq;
using System.Net;
using Battle.Net.Infrastructure;
using Battle.Net.Managers;
using Battle.Net.Model;

namespace Battle.Net
{
    public class BattleNetConnection
    {
        public Host Host { get; set; }
        public Locale Locale { get; set; }
        public AuthenticationKeys AuthenticationKeys { get; set; }
        public bool SSL { get; set; }
        public bool UseCache { get; set; }
        public string CacheConnectionString { get; set; }

        public BattleNetConnection(Host host, Locale locale)
        {
            Host = host;
            Locale = locale;

            Characters = new CharacterManager(){Connection = this};
            Items = new ItemManager() {Connection = this};
            Guilds = new GuildManager() {Connection = this};
            Auctions = new AuctionManager() {Connection = this};
            Spells = new SpellManager() {Connection = this};

        }

        internal T Get<T>(WebRequests request, params object[] args)
            where T : class
        {
            var reqUri = "";
            var uri = "";

            if (args[0].GetType() == typeof (Uri))
            {
                reqUri = args[0].ToString();
                uri = reqUri;
            }
            else
            {
                reqUri = String.Format("{0}{1}",
                                       String.Format(request.ToEnumString(), args),
                                       String.Format("?locale={0}", Locale.ToEnumString())
                    );

                uri = String.Format("http{0}://{1}{2}",
                                    SSL ? "s" : "",
                                    Host.ToEnumString(),
                                    reqUri);
            }


            String response = null;
            if (UseCache && CacheConnectionString != null)
            {
                response = FetchFromCache(uri);
            }

            try
            {
                if (response == null)
                {

                    if (AuthenticationKeys != null)
                    {
                        var headers = Authentication.CreateHeader(reqUri, AuthenticationKeys);
                        response = JsonFetcher.Fetch(headers, uri);
                    }
                    else
                    {
                        response = JsonFetcher.Fetch(uri);
                    }
                }

                var obj = new TypeConverter<T>().Convert(response);
                if (CacheConnectionString != null) CacheManager.InsertRequest(uri, response, CacheConnectionString);
                return obj;
            }
            catch (WebException webex)
            {
                var webResponse = webex.Response;
                if (webResponse == null) throw;

                if (webResponse.ContentType.Contains("application/json"))
                {
                    var stream = webResponse.GetResponseStream();
                    if (stream == null) throw;

                    var reader = new StreamReader(stream);
                    var json = reader.ReadToEnd();

                    var error = new TypeConverter<BattleNetError>().Convert(json);
                    error.Args = args;
                    error.Request = uri;
                    throw new BattleNetException(error, webex);
                }

                throw;
            }

        }

        private string FetchFromCache(string url)
        {
            var cm = new CacheManager(CacheConnectionString);
            return cm.Set<CachedResponse>().Where(cr => cr.Request == url).Select(cr => cr.Response).SingleOrDefault();
        }

        public CharacterManager Characters { get; set; }
        public ItemManager Items { get; set; }
        public GuildManager Guilds { get; set; }
        public AuctionManager Auctions { get; set; }
        public SpellManager Spells { get; set; }
    }
}
